package io.github.yotta.export.core.export.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.github.yotta.common.api.model.ApiPageRequest;
import io.github.yotta.common.api.model.Paging;
import io.github.yotta.export.core.enums.ExcelType;
import io.github.yotta.export.core.export.ExcelDataExporter;
import io.github.yotta.export.core.model.ExecuteContext;
import io.github.yotta.export.core.provider.FileProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author yotta
 * @date 2023/10/30 8:49
 */
@Slf4j
public class EasyExcelExporterExecutor extends AbstractExporterExecutor {
    public EasyExcelExporterExecutor(ExecutorService executorService, FileProvider fileProvider) throws IOException {
        super(executorService, fileProvider);
    }

    public EasyExcelExporterExecutor(FileProvider fileProvider) throws IOException {
        this(Executors.newFixedThreadPool(5,
                new ThreadFactoryBuilder()
                        .setNameFormat("DataExportExecutorThread-%d")
                        .setDaemon(false).build()), fileProvider);
    }

    @Override
    protected <R extends ApiPageRequest, M> Long doExport(R exportParam, ExcelDataExporter<M, R> dataExporter,
                                                          ExecuteContext dataExecuteContext, OutputStream outputStream) {
        long exportedCount = 0L;
        final String sheetName = dataExporter.sheetName(exportParam, dataExecuteContext);
        try (ExcelWriter excelWriter = getExcelWriter(exportParam, dataExporter, dataExecuteContext, outputStream)) {
            WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
            while (true) {
                Integer pageNo = exportParam.getPageNo();
                // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
                final Paging<M> pageResult = dataExporter.exportData(exportParam, dataExecuteContext);
                List<M> dataSet = pageResult.getData();
                if (CollectionUtils.isEmpty(dataSet)) {
                    break;
                } else {
                    excelWriter.write(dataSet, writeSheet);
                    exportParam.setPageNo(++pageNo);
                    exportedCount += dataSet.size();
                }
            }
        }
        return exportedCount;
    }

    /**
     * TODO: 考虑将ExcelWriter的配置可以交给用户配置
     */
    protected <R extends ApiPageRequest, M, C extends ExecuteContext> ExcelWriter getExcelWriter(R exportParam,
                                                                                                 ExcelDataExporter<M, R> dataExporter,
                                                                                                 ExecuteContext dataExecuteContext,
                                                                                                 OutputStream outputStream) {
        return EasyExcel.write()
                // TODO: 应该根据数据量的多少来选择是否在内存中完成导出
                .inMemory(false)
                .head(dataExporter.modelClass())
                .excelType(ExcelType.toEasyExcelTypeEnum(dataExporter.excelType(exportParam, dataExecuteContext)))
                .file(outputStream)
                .build();
    }


}
